package Apriori;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;

/**
 * @author Yilin/YichaoSun
 */
public class CalcSupport{

   private ArrayList<HashSet<String>> transList = new ArrayList<HashSet<String>>();   //List all the transactions
   private HashMap<ArrayList<String>, Integer> tempL = new HashMap<ArrayList<String>, Integer>(); 
   private HashMap<ArrayList<String>, Integer> largeItemSet = new HashMap<ArrayList<String>, Integer>();
   double minSupport;
   
   public CalcSupport(ArrayList<HashSet<String>> transList, double minSupport){
       this.transList = transList;
       this.minSupport = minSupport;
       Apriori();
   }
   
   private HashMap<ArrayList<String>, Integer> NextStep(HashMap<ArrayList<String>, Integer> tmpL){
       
       HashMap<ArrayList<String>, Integer> dupL = (HashMap<ArrayList<String>, Integer>) tmpL.clone();
       HashMap<ArrayList<String>, Integer> stepResult = new HashMap<ArrayList<String>, Integer>();
       
       Iterator<ArrayList<String>> tmpLiter1 = tmpL.keySet().iterator();
       while(tmpLiter1.hasNext()){
           ArrayList<String> p = tmpLiter1.next();
           Iterator<ArrayList<String>> tmpLiter2 = tmpL.keySet().iterator();
           while(tmpLiter2.hasNext()){
               ArrayList<String> q = tmpLiter2.next();
               int tmpK = q.size();
               ArrayList<String> tmpCombi = new ArrayList<String>();
               boolean flag = false;
               for( int i=0; i< tmpK-1 ; i++){
                   if(!p.get(i).equals(q.get(i))){
                       flag = true;
                       break;
                   }
               }
               
               if (p.get(tmpK-1).equals(q.get(tmpK-1))){
			flag = true;
	       }
               
               if( flag == false){  //qualified to be considered
                   for( int j=0; j< tmpK-1; j++){
                       tmpCombi.add(p.get(j));
                   }
                   if( p.get(tmpK-1).compareTo(q.get(tmpK-1)) < 0){
                       tmpCombi.add(p.get(tmpK-1));
                       tmpCombi.add(q.get(tmpK-1));
                   }else{
                       tmpCombi.add(q.get(tmpK-1));
                       tmpCombi.add(p.get(tmpK-1));
                   }
               }
               
               if (!stepResult.containsKey(tmpCombi)) {
                        stepResult.put(tmpCombi, 0);
	       }
               
           }
       }
       
       HashMap<ArrayList<String>, Integer> dupStepResult = (HashMap<ArrayList<String>, Integer>) stepResult.clone();
       Iterator<ArrayList<String>> dupSRiter = stepResult.keySet().iterator();
       while(dupSRiter.hasNext()){
           ArrayList<String> tmp = dupSRiter.next();
           Iterator<String> tmpIter = tmp.iterator();
           while(tmpIter.hasNext()){
               String tmpStr = (String)tmpIter.next();
               ArrayList<String> tmpClone = (ArrayList<String>)tmp.clone();
               tmpClone.remove(tmpStr);
               if(!dupL.containsKey(tmpClone)){
                   dupStepResult.remove(tmp);
                   break;
               }
           }
       }
       stepResult.clear();
       stepResult = dupStepResult;
       
       return stepResult;
   }
   
   private void Apriori(){
       
       //Find all the large single item set first
       HashMap<String, Integer> tmpOneItemSet = new HashMap<String, Integer>();
       Iterator<HashSet<String>> singleTrans = transList.iterator();
       while(singleTrans.hasNext()){
           HashSet<String> tempItemSet = (HashSet<String>)singleTrans.next();
           Iterator<String> singleItem1 = tempItemSet.iterator();
           while(singleItem1.hasNext()){
               String singleItem = (String)singleItem1.next();
               if(tmpOneItemSet.containsKey(singleItem)){
                   int tmpValue = (Integer)tmpOneItemSet.get(singleItem)+1;
                   tmpOneItemSet.put(singleItem, tmpValue);
               }else{
                   tmpOneItemSet.put(singleItem, 1);
               }
           }  
       }
       Iterator<String> tmpOneItemSetIter = tmpOneItemSet.keySet().iterator();
       while(tmpOneItemSetIter.hasNext()){
           String item = (String)tmpOneItemSetIter.next();
           if((Integer)tmpOneItemSet.get(item) >= minSupport * transList.size()){
               ArrayList<String> tmpList = new ArrayList<String>();
               tmpList.add(item);
               tempL.put(tmpList, (Integer)tmpOneItemSet.get(item));
           }
       }
       
       //The Iteration
       while(!tempL.isEmpty()){
           Iterator<ArrayList<String>> tmpLIter = tempL.keySet().iterator();
           while(tmpLIter.hasNext()){
               ArrayList<String> prevSet = tmpLIter.next();
               largeItemSet.put(prevSet, tempL.get(prevSet));
           }
           
           HashMap<ArrayList<String>, Integer> Ck = NextStep(tempL);
           HashMap<ArrayList<String>, Integer> dupCk = (HashMap)Ck.clone();
           
           Iterator transLiter = transList.iterator();
           while(transLiter.hasNext()){
               HashSet<String> singleT = (HashSet<String>)transLiter.next();
               Iterator<ArrayList<String>> Ckiter = Ck.keySet().iterator();
               while(Ckiter.hasNext()){
                   ArrayList<String> singleC = Ckiter.next();
                   if(singleT.containsAll(singleC)){
                       int tmpValue = (Integer) dupCk.get(singleC)+1;
                       dupCk.put(singleC, tmpValue);
                   }
               }
           }
           Ck.clear();
           Ck = (HashMap<ArrayList<String>, Integer>) dupCk.clone();
           dupCk.clear();
           
           //Filter the item set with support less than min-support
           tempL.clear();
           Iterator<ArrayList<String>> Ckiter = Ck.keySet().iterator();
           while(Ckiter.hasNext()){
               ArrayList<String> singleCk = Ckiter.next();
               if( (Integer)Ck.get(singleCk) >= minSupport * transList.size()){
                   tempL.put(singleCk, Ck.get(singleCk));   //the Lk for this step
               }
           }
       }
       
       
   }
   
   public HashMap<ArrayList<String>, Integer> GetLargeItemSet(){
       return largeItemSet;
   }
}
